package server.conn;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;

import server.Logger;
import server.user.User;

public abstract class ConnectionThread extends Thread {
	public static final String SPLIT = "||";
	public static final String OK = "OK";
	public static final String ERROR = "ERROR";
	public static final String LOGIN = "LOGIN";
	public static final String BYE = "BYE";
	
	public static final int EXIT = 000;
	
	protected Socket socket;
	protected PrintWriter out;
	protected BufferedReader in;
	protected ConnectionController parent;
	protected User user;
	protected boolean checkable;
	protected volatile boolean working;
	protected String name;
	
	/**
	 * Creates a new ConnectionThread
	 * @param socket	Socket for the connection
	 * @param parent	Parent ConnectionController
	 * @param group		ThreadGroup to join
	 * @param name		Name for the ConnectionThread
	 */
	public ConnectionThread(Socket socket, ConnectionController parent, ThreadGroup group, String name) {
		super(group, "UserConnectionThread");
		this.socket = socket;
		this.parent = parent;
		this.working = true;
		this.name = name;
		user = null;
		checkable = false;
	}
	
	/**
	 * Stop listening for commands and end thread
	 */
	public void kill() { working = false; }
	
	/**
	 * Make connection to client and begin working
	 */
	public void run() {
		try {
			out = new PrintWriter(socket.getOutputStream(), true);
			in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
			Logger.getInstance().addLog("Connection made to: "+getClient()+" in "+name,4);
			
			checkLogin();
			
			out.close();
			in.close();
			socket.close();
		} catch (IOException e) {
			Logger.getInstance().addError("IO Exception in User",2);
			working = false;
		}
		Logger.getInstance().addLog("Connection closed to: "+getClient()+".",4);
	}
	
	/**
	 * Check login
	 */
	protected abstract void checkLogin();
	
	/**
	 * Called after user has logged in
	 */
	protected abstract void doCommands();
	
	/**
	 * Read a line from socket
	 * @return	The line read
	 * @throws IOException
	 */
	protected String readLine() throws IOException { return in.readLine(); }
	
	/**
	 * Print a line of text over the socket
	 * @param line	Line of text to print
	 */
	protected void printLine(String line) { out.println(line); }
	
	/**
	 * Print an array of lines over the socket
	 * @param lines		Array of lines to print
	 */
	protected void printArray(String[] lines) {
		printLine(lines.length+"");
		for (String line : lines) {
			printLine(line);
		}
	}
	
	/**
	 * Print an error over the socket and log it locally
	 * @param msg		Error message
	 * @param level		Error level
	 */
	protected void printError(String msg, int level) {
		printLine(ERROR+SPLIT+msg);
		Logger.getInstance().addError("("+getClient()+") "+msg, level);
	}
	
	/**
	 * Return the client's hostname
	 * @return	Client's hostname
	 */
	protected String getClient()  {return socket.getInetAddress().getHostName(); }
	
	/**
	 * If the thread is checkable return its user's username
	 * @return	Username
	 */
	protected String getUserName() { return (checkable) ? user.getUserName() : ""; }
}
